Porky Pig 头像的花式悬停效果

您所在的位置:网站首页 radial gradient用法 Porky Pig 头像的花式悬停效果

Porky Pig 头像的花式悬停效果

#Porky Pig 头像的花式悬停效果| 来源: 网络整理| 查看: 265

20230427123226.gif

猪小弟的动画想必很多人小时候都看过,那长大的我们做了前端的工作,有没有用前端的想法去思考,猪小弟从圆圈里出来挥手的效果是如何实现的呢?

如果用这个效果来作为头像的效果,不仅有3D的感觉,而且仿佛头像在与人互动一样。这显然要比一张图片来的有意思,话不多说,让我们来看看实现后的效果。

confirm.gif

看到了吗?我们将制作一个缩放动画,其中头像似乎从它所在的圆圈中弹出。很有意思吧,不要翻到页尾哦,让我们一起逐步构建这个动画效果吧!

image.png

唯一的 img

看过实现效果后,我们可能会想到用一个 div 和一个 img 元素来实现,然后 hover 和 transform: scale 来控制缩放,overflow 来控制显示范围,可是结果却不行,效果是这样的。

error.gif

实际情况呢,我们仅需一个 元素就可以实现。什么?你不信?

image.png

那就让我们用这唯一的 img 元素来实现一下,从中你将学到 CSS 渐变、遮罩、outline 属性的行为、转换以及其他许多内容。

实现

我们先从 transform 开始,其中用到了 css 的变量,对 css 变量还不了解的小伙伴可以点击链接去看一下,这里就不详细赘述了。

img { /* 头像的大小 */ --s: 280px; /* 边框的宽度 */ --b:5px; width: var(--s); height: var(--s); cursor: pointer; outline: var(--b) solid; transition: 0.5s; } img:hover { transform: scale(1.35); } 复制代码

01.gif

边框与背景

这很简单,接下来实现图片圆形的边框与背景,这个边框我们用什么实现呢?有人说边框,直接用 border 不就行了, 可是 border 的话就会随着图片的大小一起被缩放。所以这里我们可以使用径向渐变,因为径向渐变我们可以单独控制,而且渐变之间可以硬停止,我们可以用它来绘制背景和边框,这是个完美的解决方案。

但是在写径向渐变之前我们要了解渐变尺寸的几个关键字

image.png

从上图中我们可以看出,效果一与效果二才是我们想要的,而径向渐变的默认值是效果四的样子,所以在我们实现渐变时,要使用的是效果一的关键字。

img { /* 定义背景色的变量 */ --bgColor: #ecd078; /* 定义边框颜色的变量 */ --borderColor: #c02942; /* circle 定义渐变为圆形,closest-side 让渐变以元素的最短边为半径 */ /* 然后设置渐变的颜色范围( 99% 是为了解决渐变的锯齿问题 ),no-repeat center 让渐变不重复且居中 */ background: radial-gradient(circle closest-side, var(--bgColor) calc(99% - var(--b)), var(--borderColor) calc(100% - var(--b)), var(--borderColor) 99%, lightblue 100%) no-repeat center; /* etc... */ } 复制代码

02.gif

下一步我们要做的是在悬停时调整渐变大小,随着头像的放大,渐变需要保持其大小。由于我们正在使用的 scale 是放大,所以我们实际上需要减小渐变的大小,否则它会随着头像而放大。因此,当头像放大时,我们需要渐变来缩小。也就是说我们头像放大几倍,渐变就要缩小几倍,那么就可以使用 100% / 放大的倍数 来得到渐变的大小。

img { /* 定义一个比例值 */ --f: 1; /* 我们在这里控制头像的放大就可以 */ transform: scale(var(--f)); /* calc(100% / var(--f)):横向保持不变 */ /* 100%:纵向跟随头像变化 */ background: radial-gradient(circle closest-side, var(--bgColor) calc(99% - var(--b)), var(--borderColor) calc(100% - var(--b)), var(--borderColor) 99%, lightblue 100%) no-repeat center / calc(100% / var(--f)) 100%; /* etc... */ } img:hover { /* 在鼠标移入时改变比例值的大小 */ --f: 1.35; } 复制代码

03.gif

我们又成功的完成了一步,但我们仍然需要隐藏头像的身体部分,这是最麻烦的部分,也是我们接下来要做的事情。

image.png

底部边框

因为渐变是一个背景,所以图片是覆盖在渐变之上的,我们要让红色的边框压在图片上边,我们就要使用一个新的东西来压一下,使用 border 的话显示是不可以的,因为他会随着头像的放大而放大,而 outline 可以做到 border 做不到的事情。

在实现之前我们先来认识了解一下 outline 中的一个关键属性,outline-offser,属性用于设置 outline 与一个元素边缘或边框之间的间隙,效果如下。

image.png

我们需要 outline 覆盖在边框之上,而默认值是紧贴着,所以我们在使用时要使用负值将 outline 向内收缩边框的宽度就可以了。

img { /* 将 outline 的颜色改变为边框的颜色 */ outline: var(--b) solid var(--borderColor); /* 将 outline 向内缩小距离,重合在边框之上 */ outline-offset: calc(0px - var(--b)); /* 上边的两个角不变,下边的两个角设置数值大点变为圆角,使轮廓与渐变的弯曲程度相匹配 */ border-radius: 0 0 500px 500px; /* etc... */ } 复制代码

04.gif

我们再来思考一下如何让头像缩放时 outline 保持不变永远覆盖在边框之上呢?我们画个图看一下。

image.png

由上图所示我们得到了我们想要的值,那么我们将结果套入代码之中。

img { /* 将得到的结果套入代码之中,相应的值换成变量 */ outline-offset: calc((1 / var(--f) - 1) * var(--s) / 2 - var(--b)); /* etc... */ } 复制代码

01.gif

现在已经看起来越来越有意思了,我们接下来就是要去除挡在头发的线,这个很简单,让我们在顶部添加带有填充的空间,以帮助避免顶部的重叠。

img { /* 向顶部添加带有填充的空间 */ padding-top: calc(var(--s) / 5); /* etc... */ } 复制代码

image.png

得到效果如上图所示,这是因为背景图默认填充的是 padding 的范围,我们只需要更改背景图的填充范围即可。

img { /* 添加 content-box 属性,让背景图在内容盒中 */ background: radial-gradient(circle closest-side, var(--bgColor) calc(99% - var(--b)), var(--borderColor) calc(100% - var(--b)), var(--borderColor) 99%, lightblue 100%) content-box no-repeat center / calc(100% / var(--f)) 100%; /* etc... */ } 复制代码

02.gif

到这里我们基本实现了效果,如果忽视掉圆圈外的干扰我们就已经完成了,所以接下来我们的最后一步就是框一个范围,让范围内的内容呈现范围外的隐藏,这时候就要依靠我们的压轴属性了 mask。

image.png

mask

image.png

由上图我们可以看出黄色框住的部分是我们要显示的部分,黄色框由一个矩形和一个圆形组成,并且我们发现一下两点。

圆形部分与我们的渐变背景大小完全一致,曲率相同,控制缩放自然也是相同的。 矩形部分覆盖的是 outline 之内的区域,也就是说矩形的宽度是 outline 减去边框的宽度。

那我们来使用 mask 实现这个两个区域。

img { /* 因为圆形部分与我们渐变背景大小一致 */ /* 所以圆形部分的 mask 几乎与渐变背景的样式相同,我们提取一下公告部分,定义一个变量 --_g */ --_g: content-box no-repeat center / calc(100% / var(--f)) 100%; background: radial-gradient(circle closest-side, var(--bgColor) calc(99% - var(--b)), var(--borderColor) calc(100% - var(--b)), var(--borderColor) 99%, lightblue 100%) var(--_g); -webkit-mask: radial-gradient(circle closest-side, #000 99%, #0000) var(--_g); /* etc... */ } 复制代码

03.gif

接下来,还有一个矩形部分,linear-gradient。

img { --_o: calc((1 / var(--f) - 1) * var(--s) / 2 - var(--b)); outline-offset: var(--_o); -webkit-mask: linear-gradient(#000 0 0) no-repeat 50% calc(1px - var(--_o)) / calc(100% / var(--f) - 2 * var(--b) - 2px) 50%, radial-gradient(circle closest-side, #000 99%, #0000) var(--_g); } 复制代码

矩形部分的代码可能不太容易理解,我们暂时将 img 中的 background 与 -webkit-mask 注释掉,给 img 添加一个纯色的背景让他不重复且居中。

img { /* background: radial-gradient(circle closest-side, var(--bgColor) calc(99% - var(--b)), var(--borderColor) calc(100% - var(--b)), var(--borderColor) 99%, #0000 100%) var(--_g); -webkit-mask: linear-gradient(#000 0 0) no-repeat 50% calc(1px - var(--_o)) / calc(100% / var(--f) - 2 * var(--b) - 2px) 50%, radial-gradient(circle closest-side, #000 99%, #0000) var(--_g); */ background: linear-gradient(#000 0 0) no-repeat center; } 复制代码

04.gif

我们就得到了这样的一个效果,可以看到背景上移了,而 outline 并没有动,回顾一下我们控制 outline 的逻辑,outline 的收缩大小正好是我们背景上移的大小,只不过 outline 收缩是负值,背景向下移动需要正值,我们来写一下。

img { /* 因为 outline 的收缩与背景的下移有相同的代码,所以我们创建一个新的变量 --_o */ --_o: calc((1 / var(--f) - 1) * var(--s) / 2 - var(--b)); outline-offset: var(--_o); /* calc(0px - var(--_o)) 取 outline 的正值*/ background: linear-gradient(#000 0 0) no-repeat center calc(0px - var(--_o)); } 复制代码

05.gif

好了,现在我们的背景图位置正确了,让我们来处理一下他的大小问题。

img { /* calc(100% / var(--f)) 因为横向的尺寸放大了,所以我们让他除以放大的比例 */ /* 50% 纵向的尺寸在整个过程中没有变化,我们让他一直保持就行 */ background: linear-gradient(#000 0 0) no-repeat center calc(0px - var(--_o)) / calc(100% / var(--f)) 50%; } 复制代码

06.gif

可以看到现在的效果已经很好了,那么现在我们将 background 的代码当作矩形的代码合并到 -webkit-mask 中,将原先注释的代码还原,这里不要忘了,我们考虑过矩形的宽度是 outline 减去两边边框的宽度,要一并写入其中。并将背景色改为透明色。

img { /* #0000 表示纯黑色的透明色 */ background: radial-gradient(circle closest-side, var(--bgColor) calc(99% - var(--b)), var(--borderColor) calc(100% - var(--b)), var(--borderColor) 99%, #0000 100%) var(--_g); /* calc(100% / var(--f) - 2 * var(--b)) 在宽度的控制中减去两倍的边框宽度 */ -webkit-mask: linear-gradient(#000 0 0) no-repeat 50% calc(1px - var(--_o)) / calc(100% / var(--f) - 2 * var(--b)) 50%, radial-gradient(circle closest-side, #000 99%, #0000) var(--_g); } 复制代码

到这里我们已经完全完成了,但是效果并不完美还有一个小小的 bug 存在,让我们看一下现在的效果,找找 bug 在哪。

07.gif

眼神好的同学可能已经发现了,在头像缩放时会有很细的线闪动,这是因为我们在绘制 mask 矩形时完全是贴着 outline 的内边的,这就导致在缩放时由于绘制的问题导致不能完美的实现,所以我们可以在矩形减去边框时多减去一点点。

img { /* calc(100% / var(--f) - 2 * var(--b) - 2px) 多减去 2px */ -webkit-mask: linear-gradient(#000 0 0) no-repeat 50% calc(1px - var(--_o)) / calc(100% / var(--f) - 2 * var(--b) - 2px) 50%, radial-gradient(circle closest-side, #000 99%, #0000) var(--_g); } 复制代码

我们再来看看最终的效果。

08.gif

总结

一个小小的头像效果考察到了我们很多 css 的知识, 我们使用一个 img 元素和一些 css 的技巧以及数学公式来完成了这个头像的花式悬停效果,很多小细节都在其中,我们今天探究这个头像效果实现,其实也是检验我们基本功的过程。有句古话说:合抱之木,生于毫末;九层之台,起于垒土;千里之行,始于足下。更高的薪资建立在更牢固的基础之上,让我们温故而知新,努力学习吧!

下面是全部的代码和原始图片,喜欢的小伙伴可以跟着上面的过程自己写一遍。

img { --s: 280px; --b: 5px; --bgColor: #ecd078; --borderColor: #c02942; --f: 1; --_g: 50% / calc(100% / var(--f)) 100% no-repeat content-box; --_o: calc((1 / var(--f) - 1) * var(--s) / 2 - var(--b)); width: var(--s); height: var(--s); cursor: pointer; padding-top: calc(var(--s) / 5); outline: var(--b) solid var(--borderColor); outline-offset: var(--_o); border-radius: 0 0 500px 500px; transition: 0.5s; transform: scale(var(--f)); background: radial-gradient(circle closest-side, var(--bgColor) calc(99% - var(--b)), var(--borderColor) calc(100% - var(--b)), var(--borderColor) 99%, #0000 100%) var(--_g); -webkit-mask: linear-gradient(#000 0 0) no-repeat 50% calc(1px - var(--_o)) radial-gradient(circle closest-side, #000 99%, #0000) var(--_g); } img:hover { --f: 1.35; } 复制代码

avatar.png

备注:学习来源 渡一Web前端学习频道



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3